﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using TopVidionApplication;
using TopVisionLog;
using TopVisionVideoStream;
using VideoStream.Common;
using VideoStream.CustomControl;
using VideoStream.Model;
using VideoStream.Properties;
using System.Linq;
using System.Media;
using VideoStream.Net;

namespace VideoStream.Windows
{
    public partial class Windows_Main : VideoStream.Windows.WindowsBase
    {
        public static Windows_Main Instance;

        private Size anableMaximuSize => Screen.GetWorkingArea(this.PointToScreen(this.Location)).Size;
        private WindowsBase winLogin;
        private WindowsBase winVideoCall;
        private WindowsBase winDisplay;
        private WindowsBase winVideoLookBack;
        private WindowsBase winScreenGrid;
        private WindowsBase winSetting;
        private List<WindowsBase> winList = new List<WindowsBase>();
        private Panel panelMask;
        private List<PictureButton> menuGroup => table_Menu.Controls.OfType<PictureButton>().ToList();
        private SoundPlayer soundPlayer;

        private DateTime TraficStart;
        private DateTime TraficEnd;

        private bool wantQuit = false;
        private bool menuActive = true;
        public bool IsLogin = false;



        #region Property

        public bool MenuActive
        {
            get { return menuActive; }
            set
            {
                menuActive = value;
                MenuAction(MenuActive);
            }
        }
        public Windows_Display WinDisplay
        {
            get { return winDisplay as Windows_Display; }
        }

        #endregion

        public Windows_Main()
        {
            if (Instance == null)
            {
                Instance = this;
            }
            else if (Instance != this)
            {
                Console.WriteLine("Singleton err : " + this.Name);

                Hide();
                Close();
                return;
            }

            InitializeComponent();
            InitUI();
        }

        #region Override Method

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            InitEvent();
            UpdateUI();

            ShowLoginWindows();
            //Network();
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            var ret = Logout(true);
            e.Cancel = !ret;
            base.OnFormClosing(e);
        }

        protected override void OnClosed(EventArgs e)
        {
            CommonFun.CloseUpdateApp();
            base.OnClosed(e);
        }

        public override void InitEvent()
        {
            base.InitEvent();

            // windows event
            this.SizeChanged += Windows_Main_SizeChanged;

            btn_CtlBoxSubMenu.Click += Btn_CtlBoxSubMenu_Click;

            foreach (Control item in panel_Bottom.Controls)
            {
                item.MouseDown += MoveWindows;
            }
            table_Menu.MouseDown += MoveWindows;
            pic_Logo.MouseDown += MoveWindows;
            panel_MenuAccount.MouseDown += MoveWindows;

            // Sub Menu
            tsm_Logout.Click += Tsm_Logout_Click;
            tsm_SafeQuit.Click += Tsm_SafeQuit_Click;

            // Tvvs Event
            TVVS.VideoCallResult += TVVS_VideoCallResult;
            TVVS.VideoCallMe += TVVS_VideoCallMe;
            TVVS.MessageInfoEvent += TVVS_MessageInfoEvent;
            TVVS.TrafficNotifyEvent += TVVS_TrafficNotifyEvent;

            // Menu control
            btn_MenuVideoCall.Click += MenuClick;
            btn_MenuVideoLookBack.Click += MenuClick;
            btn_MenuScreen.Click += MenuClick;
            btn_MenuSetting.Click += MenuClick;


            // Control box
            btn_CtlBoxClose.Click += Btn_CtlBoxClose_Click;
            btn_CtlBoxResume.Click += Btn_CtlBoxResume_Click;
            btn_CtlBoxMin.Click += Btn_CtlBoxMin_Click;

            // Network
            NetworkManager.Instance.ConnectedToInternetEvent += NetworkManager_Connected;
            NetworkManager.Instance.ConnectedEvent += NetworkManager_ConnectedToInternet;
            NetworkManager.Instance.NetWorkChangedEvent += NetworkManager_NetWorkChangedEvent;
        }

        public override void InitUI()
        {
            base.InitUI();
            this.ShowTitle = false;
            this.Width = 1000;
            this.Height = 660;
            this.MaximumSize = anableMaximuSize;
        }

        public override void UpdateUI()
        {
            base.UpdateUI();

            tsm_About.Text = TVString.STR_About;
            tsm_FeedBack.Text = TVString.STR_Feedback;
            tsm_Logout.Text = TVString.STR_SwitchAccount;
            tsm_SafeQuit.Text = TVString.STR_SafeQuit;

            btn_MenuVideoCall._Text = TVString.STR_VideoCall;
            btn_MenuVideoLookBack._Text = TVString.STR_VideoLookBack;
            btn_MenuScreen._Text = TVString.STR_Screen;
            btn_MenuSetting._Text = TVString.STR_Setting;

            lab_Company.Text = TVString.STR_Support + ":" + CommonFun.AssemblyCompany;
            lab_Version.Text = CommonFun.AssemblyVersion;

            panel_MenuAccount.Hide();
            MenuActive = false;

        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == (Keys.Alt | Keys.Space))
            {
                Btn_CtlBoxSubMenu_Click(null, null);
            }

            if (keyData == Keys.Enter) Console.WriteLine("Win Main Enter >>>>>");

            return base.ProcessCmdKey(ref msg, keyData);
        }

        #endregion


        #region Control Event

        private void Windows_Main_SizeChanged(object sender, EventArgs e)
        {
            switch (this.WindowState)
            {
                case FormWindowState.Normal:
                    btn_CtlBoxResume.NormalBgImage = Resources.最大化;
                    break;
                case FormWindowState.Minimized:
                    break;
                case FormWindowState.Maximized:
                    btn_CtlBoxResume.NormalBgImage = Resources.还原;
                    break;
                default:
                    break;
            }
            if (panelMask != null) panelMask.Size = panel_Content.Size;
        }

        private void Btn_CtlBoxMin_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void Btn_CtlBoxResume_Click(object sender, EventArgs e)
        {
            if (WinDisplay != null)
            {
                if (!WinDisplay.IsDisposed)
                {
                    if (WinDisplay.IsMark | WinDisplay.IsPhoto | WinDisplay.IsSrcShot)
                    {
                        Windows_MessageBox wmb = new Windows_MessageBox(TVString.STR_IsMarkOn, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        wmb.ShowDialog(this);
                        return;
                    }
                }
            }

            this.MaximumSize = anableMaximuSize;
            switch (this.WindowState)
            {
                case FormWindowState.Normal:
                    this.WindowState = FormWindowState.Maximized;
                    break;
                case FormWindowState.Minimized:
                    break;
                case FormWindowState.Maximized:
                    this.WindowState = FormWindowState.Normal;
                    break;
                default:
                    break;
            }
        }

        private void Btn_CtlBoxClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Btn_CtlBoxSubMenu_Click(object sender, EventArgs e)
        {
            cm_Menu.Show(btn_CtlBoxSubMenu.PointToScreen(new Point(0, btn_CtlBoxSubMenu.Height)));
        }

        private void Tsm_Logout_Click(object sender, EventArgs e)
        {
            Logout();
        }

        private void Tsm_SafeQuit_Click(object sender, EventArgs e)
        {
            Logout(true);
        }

        private void MenuClick(object sender, EventArgs e)
        {
            MenuSelected(sender as PictureButton);
        }

        private void NetworkManager_NetWorkChangedEvent()
        {
            Console.WriteLine("Network Changed >>>>>>>>>>>>>>");
            if (IsLogin)
                OfflineNotify();
        }

        private void NetworkManager_ConnectedToInternet(bool connected)
        {
            Console.WriteLine("Internet Connected : " + (connected ? "连接" : "断开"));
            if (IsLogin)
                OfflineNotify();
        }

        private void NetworkManager_Connected(bool connected)
        {
            Console.WriteLine("Connected : " + (connected ? "连接" : "断开"));
            if (IsLogin)
                OfflineNotify();
        }

        #endregion


        #region TVVS Event

        private async void LogoutResult()
        {
            await Task.Delay(100);

            if (wantQuit)
            {
                AppQuit();
            }
            else
            {
                winList.ForEach(o =>
                {
                    o.Close();
                    o = null;
                });
                winList.Clear();
                MenuSelected(null);
                ShowLoginWindows();
            }
            //ApplicationData.Account = "";
        }

        private void TVVS_VideoCallResult(CallStatusType e)
        {
            switch (e)
            {
                case CallStatusType.Connected:
                    TraficStart = DateTime.Now;
                    break;
                case CallStatusType.DisConnect:
                    DisConnected();
                    break;
            }
        }

        private void TVVS_VideoCallMe(string callingID)
        {
            if (!this.Visible)
                this.Show();
            PlayerCallIn(ApplicationData.CallInRing);
            if (this.WindowState == FormWindowState.Minimized)
                this.WindowState = FormWindowState.Normal;
            this.Activate();
            ApplicationData.tmpCallInID = callingID;
            Windows_MessageBox wmb = new Windows_MessageBox(string.Format(TVString.STR_F_CallingIN, callingID), MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
            wmb.SetConfirmText(TVString.STR_Accept);
            wmb.SetCancelText(TVString.STR_Hangup);
            if (wmb.ShowDialog(this) == DialogResult.OK)
            {
                CallAccept();
            }
            else
            {
                Hangup();
            }
        }

        private void CallingResult(DialogResult dlgResult)
        {
            switch (dlgResult)
            {
                case DialogResult.OK:
                    CallAccept();
                    break;
                case DialogResult.Cancel:
                    Hangup();
                    break;
                default:
                    break;
            }
        }

        private void TVVS_MessageInfoEvent(string msg)
        {
            if (msg == "UnRegist")
            {
                Windows_MessageBox wmb = new Windows_MessageBox(TVString.STR_UnRegist, MessageBoxButtons.OK, MessageBoxIcon.Information);
                wmb.ShowDialog(this);
                Logout(false, true);
            }
        }

        private void TVVS_TrafficNotifyEvent(int audioSend, int audioRecv, int videoSend, int videoRecv)
        {
            if (!NetworkManager.Instance.IsConnectedToInternet) return;

            TraficEnd = DateTime.Now;

            string _rsFormat = "音频发送：{0} B \r\n音频接收：{1} B\r\n视频发送：{2} B\r\n视频接收：{3} B";

            Console.WriteLine(string.Format(_rsFormat, audioSend, audioRecv, videoSend, videoRecv));

            VideoFlow _videoFlow = new VideoFlow(
                ApplicationData.Account,
                ApplicationData._CompanyPro?.id.ToString(),
                TraficStart.ToString("yyyy-MM-dd HH:mm:00"),
                TraficEnd.ToString("yyyy-MM-dd HH:mm:00"),
                IPTool.IP,
                IPTool.Location,
                "PC",
                audioSend + videoSend,
                audioRecv + videoRecv);

            CommonFun.UploadVideoFlow(_videoFlow);
        }

        #endregion


        #region Method

        // Windows Control

        public void ShowLoginWindows()
        {
            if (this.IsDisposed) { Application.Exit(); return; }

            ClearMessageBox();

            this.Show();
            ShowMask(true);

            if (CheckSubWindows(winLogin)) return;

            if (winLogin != null)
            {
                if (!winLogin.IsDisposed) winLogin.Close();
                winLogin = null;
            }
            winLogin = new Windows_Login();
            winLogin.Parent = panel_Content;
            //this.Enabled = true;
            winLogin.Show();
            winList.Add(winLogin);
            panel_MenuAccount.Hide();
            MenuActive = false;
            tsm_Logout.Enabled = false;
        }

        public void ShowVideoCallWindows()
        {
            if (!IsLogin) ShowLoginWindows();

            ShowMask(true);
            if (CheckSubWindows(winVideoCall)) return;



            if (TVVS.ConferencStatus == ConferencStatusType.Conferencing)
            {
                WinDisplay.Parent = panel_Content;
                WinDisplay.Show();
                ShowMask(false);
                return;
            }

            winVideoCall = new Windows_VideoCall();
            winVideoCall.Parent = panel_Content;
            //this.Enabled = true;
            winVideoCall.Show();
            winList.Add(winVideoCall);
            MenuActive = true;
            btn_MenuAccount._Text = ApplicationData.Account;
            panel_MenuAccount.Show();
            btn_MenuVideoCall.Checked = true;
            tsm_Logout.Enabled = true;
        }

        public void ShowVideoDisplay(Windows_Display win)
        {
            MenuSelected(btn_MenuVideoCall);

            ShowMask(true);
            winDisplay = win;
            winDisplay.Parent = panel_Content;
            winDisplay.Show();
            winList.Add(winDisplay);
            winVideoCall.Close();
            winVideoCall = null;
        }

        public void CallAccept()
        {
            // setcapture
            btn_MenuVideoCall.Checked = true;
            if (TVVS.MicrophoneErr)
            {
                Windows_MessageBox wmb = new Windows_MessageBox(TVString.STR_MicrophoneError, MessageBoxButtons.OK, MessageBoxIcon.Error);
                wmb.ShowDialog(this);
                TVVS.VideoCallCancel();
                return;
            }
            TVVS.SetMicrophoneProperty(true, true, true);
            int camIndex = ApplicationData.tmpCameraIndex;
            int micIndex = ApplicationData.tmpMicrophoneIndex;
            int spkIndex = ApplicationData.tmpSpeakerIndex;
            string rsl = ApplicationData.tmpResolution;
            TVVS.SetCaptures(camIndex, spkIndex, micIndex, rsl);

            winDisplay = new Windows_Display();
            ((Windows_Display)winDisplay).DspType = ApplicationData.tmpCameraSelected == "1" ? DisplayType.TwoScreen : DisplayType.OneScreen;
            int remote = ((Windows_Display)winDisplay).RemoteHandle;
            int local = ((Windows_Display)winDisplay).LocalHandle;
            TVVS.SetScreen(remote, local);
            ShowVideoDisplay((Windows_Display)winDisplay);
            TVVS.AcceptCall();
        }

        public void Hangup()
        {
            TVVS.VideoCallCancel();
            TVVS.SpeakerVolume = 100;
            if (!this.IsDisposed)
                if (!this.Visible)
                    this.Show();
            if (IsLogin)
                ShowVideoCallWindows();
        }
        public bool Logout(bool isQuit = false, bool immediately = false)
        {
            wantQuit = isQuit;
            var ret = true;
            if (!immediately)
            {
                var msgBox = new Windows_MessageBox(wantQuit ? TVString.STR_AppQuitTip : TVString.STR_LogoutTip, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                ret = msgBox.ShowDialog(this) == DialogResult.OK;
            }

            if (ret)
            {
                IsLogin = false;
                ClearMessageBox();
                //CommonFun.NetcheckStop();
                IsLogin = false;
                TVVS.Logout(LogoutResult);
                if (!isQuit)
                {
                    Windows_MessageBox wmb = new Windows_MessageBox(TVString.STR_Logouting, MessageBoxButtons.OK, MessageBoxIcon.Information);
                    wmb.BtnConfirm.Visible = false;
                    wmb.ShowDialog(this);
                }
            }
            else
            {
                wantQuit = false;
            }

            return ret;
        }

        public void ShowMask(bool visible)
        {
            if (panelMask == null)
            {
                panelMask = new Panel();
                panelMask.BackColor = TVColor.Color_White;
                panelMask.Parent = panel_Content;
                panelMask.BringToFront();
                panelMask.Size = panel_Content.Size;
            }

            var tmp = winList.Where(o => o == null).ToList();
            tmp.ForEach(o => winList.Remove(o));
            tmp = winList.Where(o => o.IsDisposed).ToList();
            tmp.ForEach(o => winList.Remove(o));

            //if (TVVS.ConferencStatus == ConferencStatusType.Conferencing)
            //{
            //    winList.Remove(WinDisplay);
            //}

            if (visible)
                winList.ForEach(o =>
                {
                    o.Hide();
                    //o = null;
                    //winList.Remove(o);
                });

            panelMask.Visible = visible;

        }

        public void MenuSelected(int index)
        {
            MenuSelected(menuGroup[index]);
        }

        public void MenuSelected(PictureButton btn)
        {
            //btn.Enabled = false;
            menuGroup.Where(o => o != btn).ToList().ForEach(o =>
            {
                //o.Enabled = true;
                o.Checked = false;
            });
            if (btn != null)
            {
                if (btn == btn_MenuVideoCall) ShowVideoCallWindows();
                if (btn == btn_MenuVideoLookBack) ShowVideoLookBack();
                if (btn == btn_MenuScreen) ShowScreenGrid();
                if (btn == btn_MenuSetting) ShowSettingWindows();
            }
        }

        public void ShowVideoLookBack()
        {
            ShowMask(true);
            if (CheckSubWindows(winVideoLookBack)) return;



            if (TVVS.ConferencStatus == ConferencStatusType.Conferencing)
            {
                WinDisplay.Hide();
            }

            winVideoLookBack = new Windows_VideoLookBack();
            winVideoLookBack.TopLevel = false;
            winVideoLookBack.Parent = this.panel_Content;
            winVideoLookBack.Show();
            winList.Add(winVideoLookBack);
            btn_MenuVideoLookBack.Checked = true;
        }

        public void ShowScreenGrid()
        {
            ShowMask(true);
            if (CheckSubWindows(winScreenGrid)) return;

            if (TVVS.ConferencStatus == ConferencStatusType.Conferencing)
            {
                WinDisplay.Hide();
            }

            winScreenGrid = new Windows_ScreenGrid();
            winScreenGrid.TopLevel = false;
            winScreenGrid.Parent = this.panel_Content;
            winScreenGrid.Show();
            winList.Add(winScreenGrid);
            btn_MenuScreen.Checked = true;
        }

        private void ShowSettingWindows()
        {
            ShowMask(true);
            if (CheckSubWindows(winSetting))
            {
                return;
            }

            if (TVVS.ConferencStatus == ConferencStatusType.Conferencing)
            {
                WinDisplay.Hide();
            }

            winSetting = new Windows_Setting();
            winSetting.TopLevel = false;
            winSetting.Parent = this.panel_Content;
            winSetting.Show();
            winList.Add(winSetting);
            btn_MenuSetting.Checked = true;
        }

        public void AppQuit()
        {
            Hide();
            Windows_Startup.Instance.Close();
        }

        private void DisConnected()
        {
            if (!this.IsDisposed)
            {
                //ClearMessageBox();

                Hangup();

                //if (winDisplay != null)
                //{
                //    if (!winDisplay.IsDisposed)
                //        ((Windows_Display)winDisplay).Hangup();
                //    //this.Show();
                //}
                //else
                //{
                //    TVVS.VideoCallCancel();
                //}
            }
        }

        private void MenuAction(bool active)
        {
            menuGroup.ForEach(o => o.Enabled = active);
        }

        private void PlayerCallIn(string soundPath)
        {
            if (soundPlayer == null)
            {
                soundPlayer = new SoundPlayer();
            }
            //soundPlayer.Stop();
            soundPlayer.SoundLocation = soundPath;
            soundPlayer.PlayLooping();
        }

        private void OfflineNotify()
        {
            this.BeginInvoke((Action)(async () =>
           {
               IsLogin = false;

               Console.WriteLine("Is Login : " + IsLogin);

               ClearMessageBox();

               await Task.Delay(100);

               if (winVideoCall != null)
               {
                   ((Windows_VideoCall)winVideoCall).Hangup();
               }
               if (soundPlayer != null)
                   soundPlayer.Stop();
               Windows_MessageBox wmb = new Windows_MessageBox(TVString.STR_NoInternet, MessageBoxButtons.OK, MessageBoxIcon.Error);
               wmb.ShowDialog(this);
               Logout(false, true);
           }));
        }

        public async void ClearMessageBox()
        {
            await ClearMessageBoxAsync();
        }
        public async Task ClearMessageBoxAsync()
        {
            var opfs = Application.OpenForms.OfType<Windows_MessageBox>().ToList();
            opfs.ForEach(async o =>
            {
                o.Hide();
                o.Close();
                o.Dispose();
                while (!o.IsDisposed)
                {
                    await Task.Delay(17);
                }
            });
            opfs.Clear();
            while (opfs.Count > 0)
            {
                await Task.Delay(17);
            }
        }

        private bool CheckSubWindows(WindowsBase win)
        {
            if (win != null)
            {
                if (win.IsDisposed)
                {
                    win = null;
                }
                else
                {
                    win.Show();
                    ShowMask(false);
                }
            }

            return win != null;
        }


        #endregion


    }
}
